# !/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2022/7/28 11:54
# @Author : xyjiang1216
# @Email : jiangxuyan@nudt.edu.cn
# @File : mac_tbl_linker.py
# @Version: OpenTSN_planner_builder 1.0
from lib.tsn_builder_lib import host_to_net
import xml.etree.ElementTree as EleTree

from tsn_builder_struct.mac_tbl_structure import *


def link_mac_tbl(node,
                 mac_tbl,
                 reg_addr):
    # 找到该节点对应的mac表
    node_id = node['src_node']

    tbl_each_node = []
    broadcast_flag = -1

    for tbl in mac_tbl.tbl_set:
        if tbl.node_id == node_id:
            tbl_each_node = tbl.tbl_each_node
            broadcast_flag = tbl.broadcast_flag
            break

    if not tbl_each_node:
        return []

    base_addr = reg_addr.mac_tbl['addr']
    width = reg_addr.mac_tbl['width']

    dic = []  # 返回值
    entry_index = 0

    for entry in tbl_each_node:
        addr = base_addr + entry_index * width
        entry_index = entry_index + 1
        addr_str = host_to_net(addr)

        value1 = entry.byte.entry1
        value1_str = host_to_net(value1)

        value2 = entry.byte.entry2
        value2_str = host_to_net(value2)

        value3 = entry.byte.entry3
        value3_str = host_to_net(value3)

        value4 = entry.byte.entry4
        value4_str = host_to_net(value4)

        addr_value = {
            'addr': addr_str,
            'value': [value1_str, value2_str, value3_str, value4_str]
        }
        dic.append(addr_value)

    if broadcast_flag != -1:
        addr = reg_addr.broadcast_flag['addr']
        addr_str = host_to_net(addr)

        value = broadcast_flag
        value1_str = host_to_net((value & 0x100000000)>>32)
        value2_str = host_to_net(value & 0xffffffff)

        addr_value = {
            'addr': addr_str,
            'value': [value1_str, value2_str]
        }

        dic.append(addr_value)

        # [print(entry) for entry in dic]
    return dic


def _get_mac_tbl(mac_tbl_xml):
    mac_set = []
    root = EleTree.parse(mac_tbl_xml)
    node_ele_set = root.findall('node')
    for node_ele in node_ele_set:
        node_dic = {}
        node_id = node_ele.findtext('node_id')
        node_dic.update({'node_id': int(node_id)})
        broadcast_flag = node_ele.findtext('broadcast_flag')
        node_dic.update({'broadcast_flag':
                             int(broadcast_flag, 16)})
        node_dic.update({'entry_set': []})
        entry_ele_set = node_ele.findall('entry')
        for entry_ele in entry_ele_set:
            entry_ele = list(entry_ele)
            entry_dic = {}
            for ele in entry_ele:
                if ele.tag == 'valid' or ele.tag == 'reserve1' or ele.tag == 'reserve2':
                    entry_dic.update({ele.tag: int(ele.text)})
                else:
                    entry_dic.update({ele.tag: int(ele.text, 16)})
            node_dic['entry_set'].append(entry_dic)
        mac_set.append(node_dic)
    return mac_set


def _init_mac_tbl(mac_set):
    mac_tbl = MacTbl()
    for node in mac_set:
        mac_tbl_each_node = MacTblEachNode(node['node_id'],
                                           node['broadcast_flag'])
        mac_set_each_node = node['entry_set']
        for entry in mac_set_each_node:
            mac_entry = MacEntry_union()
            mac_entry.bit.valid = entry['valid']
            mac_entry.bit.reserve1 = entry['reserve1']
            mac_entry.bit.outport1 = entry['outport1']
            mac_entry.bit.outport2 = entry['outport2']
            mac_entry.bit.dmac_1 = entry['dmac_1']
            mac_entry.bit.dmac_2 = entry['dmac_2']
            mac_entry.bit.reserve2 = entry['reserve2']
            mac_tbl_each_node.append_entry(mac_entry)
        mac_tbl.append_tbl(mac_tbl_each_node)
    return mac_tbl


def read_mac_tbl(mac_tbl_xml):
    mac_set = _get_mac_tbl(mac_tbl_xml)
    # print('DEBUG')
    # [print(entry) for entry in mac_set]
    mac_tbl = _init_mac_tbl(mac_set)

    return mac_tbl


def main():
    mac_tbl_xml = '../output_xml/tbl_xml/mac_tbl.xml'
    read_mac_tbl(mac_tbl_xml)


if __name__ == '__main__':
    main()
